package goapk

import (
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"strings"

	"bytes"

	"gitee.com/kin9-0rz/goapk/dex"
	"github.com/avast/apkparser"
)

// APK 定义APK的结构
type APK struct {
	reader *apkparser.ZipReader
	path   string
	xml    string

	strings    []string // 存放dex字符串
	dexClasses []dex.Class
	dexFile    dex.File
	// resources *ResourceTable
	// cert string
}

// NewAPK 新建一个APK对象，一次性全部解析完毕，然后，再放在内存进行检索
func NewAPK() *APK {
	return &APK{
		path:       "",
		strings:    make([]string, 0),
		dexClasses: make([]dex.Class, 0),
	}
}

// Parse 解析指定APK文件
func (a *APK) Init(path string) error {
	zr, err := apkparser.OpenZip(path)
	if err != nil {
		// fmt.Fprintln(os.Stderr, err)
		return err
	} else {
		a.path = path
		a.reader = zr
	}

	return nil
}

// ParseBytes 解析APK的文件，内存的方式
func (a *APK) InitBytes(bs []byte) error {
	reader := bytes.NewReader(bs)
	zr, err := apkparser.OpenZipReader(reader)
	if err != nil {
		return err
	} else {
		a.reader = zr
	}
	return nil
}

// Close 关闭
func (a *APK) Close() {
	a.reader.Close()
}

// GetAndroidManifest 获取清单内容
func (a *APK) GetAndroidManifest() string {
	if a.xml == "" {
		a.ParseAndroidManifest()
	}
	return a.xml
}

// ParseAndroidManifest 解析清单内容
func (a *APK) ParseAndroidManifest() {
	buf := bytes.NewBufferString("")
	enc := xml.NewEncoder(buf)
	parser, reserr := apkparser.NewParser(a.reader, enc)
	if reserr != nil {
		fmt.Fprintf(os.Stderr, "Failed to parse resources: %s\n", reserr.Error())
	}
	err := parser.ParseXml("AndroidManifest.xml")

	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	a.xml = buf.String()
}

// ParseDexs 解析所有的Dex
func (a *APK) ParseDexs() {
	for _, f := range a.reader.File {
		if !strings.HasPrefix(f.Name, "classes") {
			continue
		}

		if !strings.HasSuffix(f.Name, ".dex") {
			continue
		}

		if err := f.Open(); err != nil {
			return
		}

		a.ParseDex(f)

		defer f.Close()
	}
}

// ParseDex 解析单个
func (a *APK) ParseDex(dexReader io.Reader) {
	dexFile, err := dex.NewFile(dexReader)
	if err != nil {
		return
	}
	a.dexFile = dexFile
	a.dexFile.ParseStrings()

	// dexFile.parseClassDefs()
	// a.dexClasses = append(a.dexClasses, dexFile.dexClasses...)
}

// GetDexStrings 获得字符串
func (a *APK) GetDexStrings() []string {
	return a.dexFile.Strings
}

// GetClass get dexclass
// func (a *APK) GetClass() []Class {
// 	return a.dexClasses
// }
